package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
import com.atguigu.tingshu.account.client.UserAccountFeignClient;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.user.client.VipServiceConfigFeignClient;
import com.atguigu.tingshu.vo.account.AccountDeductVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectReader;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Array;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private UserAccountFeignClient userAccountFeignClient;

    @Autowired
    private OrderDerateMapper orderDerateMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;


    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {
        //创建对象
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        //原始金额
        BigDecimal originalAmount = new BigDecimal("0.00");
        BigDecimal derateAmount = new BigDecimal("0.00");
        BigDecimal orderAmount = new BigDecimal("0.00");
//        订单明细
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        //减免明细
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();

        //获取用户信息
        Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(userId);
        Assert.notNull(userInfoVoResult, "查询用户失败");
        UserInfoVo userInfoVo = userInfoVoResult.getData();
        Assert.notNull(userInfoVo, "查询用户失败");
        //根据购买的类型判断
        if (tradeVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_ALBUM)) {
            //判断这个用户是否购买过专辑
            Result<Boolean> isPaidAlbumResult = this.userInfoFeignClient.isPaidAlbum(tradeVo.getItemId());
            Assert.notNull(isPaidAlbumResult, "查询用户购买专辑失败");
            Boolean result = isPaidAlbumResult.getData();
            if (result) {
                //用户购买过专辑
                throw new GuiguException(ResultCodeEnum.REPEAT_BUY_ERROR);
            }
            //购买专辑
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(tradeVo.getItemId());
            Assert.notNull(albumInfoResult, "购买专辑失败");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "购买专辑失败");

            //获取到原价
            originalAmount = albumInfo.getPrice();
            //判断用户身份
            if (userInfoVo.getIsVip().intValue() == 1 && userInfoVo.getVipExpireTime().after(new Date())) {
                //是Vip，用vip的折扣，
                if (albumInfo.getVipDiscount().compareTo(new BigDecimal("-1")) > 0) {
                    derateAmount = albumInfo.getPrice().multiply(new BigDecimal("10").subtract(albumInfo.getVipDiscount())).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
                }
            } else if (albumInfo.getDiscount().compareTo(new BigDecimal("-1")) > 0) {
                derateAmount = albumInfo.getPrice().multiply(new BigDecimal("10").subtract(albumInfo.getDiscount())).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
            }

            //实际金额
            orderAmount = originalAmount.subtract(derateAmount);
            //订单明细
            //创建订单
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVoList.add(orderDetailVo);
            //减免明细
            if (derateAmount.compareTo(new BigDecimal("0.00")) > 0) {
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                //赋值
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setRemarks("专辑折扣");
                orderDerateVoList.add(orderDerateVo);
            }
        } else if (tradeVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_TRACK)) {
            //购买声音
            //判断：当前传递的声音数量
            if (tradeVo.getTrackCount() < 0) {
                throw new GuiguException(ResultCodeEnum.ARGUMENT_VALID_ERROR);
            }
            //  当前声音数量>=0; 计算金额+订单明细{声音不包含减免}
            //  通过声音Id获取声音对象;
            //            Result<TrackInfo> trackInfoResult = trackInfoFeignClient.getTrackInfo(tradeVo.getItemId());
            //            Assert.notNull(trackInfoResult, "查询声音信息失败");
            //            TrackInfo trackInfo = trackInfoResult.getData();
            //            Assert.notNull(trackInfo, "查询声音信息失败");
            //  考虑订单明细; 与trackCount值有关系! 10; 从itemId 之后数trackCount 集;
            Result<List<TrackInfo>> trackInfoListResult = trackInfoFeignClient.findPaidTrackInfoList(tradeVo.getItemId(), tradeVo.getTrackCount());
            Assert.notNull(trackInfoListResult, "查询声音信息失败");
            //付费声音列表
            List<TrackInfo> trackInfoList = trackInfoListResult.getData();
            //当前声音Id对应的专辑Id都是同一个；
            //获取到专辑对象
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(trackInfoList.get(0).getAlbumId());
            Assert.notNull(albumInfoResult, "查询专辑信息失败");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "查询专辑信息失败");
            //原生金额：后买本集传递的Count = 0
            originalAmount = 0 == tradeVo.getTrackCount() ? albumInfo.getPrice() : albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(tradeVo.getTrackCount())));
            orderAmount = originalAmount;
            //构建订单明细
            for (TrackInfo info : trackInfoList) {
                //  创建订单明细对象
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemPrice(albumInfo.getPrice());
                orderDetailVo.setItemName(info.getTrackTitle());
                orderDetailVo.setItemUrl(info.getCoverUrl());
                //  细节记住：属于购买声音的Id，并不是页面传递的声音Id;
                orderDetailVo.setItemId(info.getId());
                orderDetailVoList.add(orderDetailVo);
            }
            //  声音不存在打折，所以没有折扣明细;

        } else {
            //购买Vip
            Long itemId = tradeVo.getItemId();
            Result<VipServiceConfig> vipServiceConfigResult = vipServiceConfigFeignClient.getVipServiceConfig(itemId);
            Assert.notNull(vipServiceConfigResult, "查询vip配置服务失败");
            VipServiceConfig vipServiceConfig = vipServiceConfigResult.getData();
            Assert.notNull(vipServiceConfig, "查询Vip配置服务失败");
            //设置原始价格
            originalAmount = vipServiceConfig.getPrice();
            //设置减免价格
            derateAmount = originalAmount.subtract(vipServiceConfig.getDiscountPrice());
            //实际金额
            orderAmount = vipServiceConfig.getDiscountPrice();
            //订单明细
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemName(vipServiceConfig.getName());
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVo.setItemId(itemId);
            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVoList.add(orderDetailVo);
            //减免明细
            if (derateAmount.compareTo(new BigDecimal("0.00")) > 0) {
                //创建对象并赋值
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setRemarks("vip服务折扣");
                orderDerateVoList.add(orderDerateVo);
            }
        }
        //声明一个订单交易号
        String tradeNo = UUID.randomUUID().toString().replaceAll("-", "");
        //存储到Redis中，判断key是否可用
        String tradeNoKey = userId + ":" + tradeNo;
        redisTemplate.opsForValue().set(tradeNoKey, tradeNo, 3, TimeUnit.MINUTES);
        orderInfoVo.setTradeNo(tradeNo);
        orderInfoVo.setPayWay("");
        orderInfoVo.setItemType(tradeVo.getItemType());
        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        orderInfoVo.setTimestamp(SignHelper.getTimestamp());
        //签名防止非法篡改数据保证接口安全性
        String orderJson = JSONObject.toJSONString(orderInfoVo);
        String sign = SignHelper.getSign(JSONObject.parseObject(orderJson, Map.class));
        orderInfoVo.setSign(sign);
        return orderInfoVo;
    }

    @Override
    @GlobalTransactional
    public String submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        //  1.  校验：签名-保证数据接口安全性! 校验orderInfoVo数据是否被篡改;
        //  orderInfoVo变为map集合;
        Map map = JSONObject.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        map.put("payWay", "");
        SignHelper.checkSign(map);
        //  2.  校验：防止重复提交订单;
        //  2.1 获取当前页面传递的流水号;
        String tradeNo = orderInfoVo.getTradeNo();
        //  2.2 与redis缓存中的流水号进行比较; 单线程-直接使用equals(); 多线程：redis+lua
        String scriptText = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                "then\n" +
                "    return redis.call(\"del\",KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";
        String tradeNoKey = userId + ":" + tradeNo;
        //  创建实现类
        DefaultRedisScript defaultRedisScript = new DefaultRedisScript<>();
        defaultRedisScript.setScriptText(scriptText);
        defaultRedisScript.setResultType(Long.class);
        //  调用方法
        Long count = (Long) redisTemplate.execute(defaultRedisScript, Arrays.asList(tradeNoKey), tradeNo);
        //  判断
        if (0 == count) {
            //  抛出异常;
            throw new GuiguException(ResultCodeEnum.REPEAT_SUBMIT);
        }
        //  声明一个订单编号;
        String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
        //  判断用户选择的支付方式：在线，余额
        if (!orderInfoVo.getPayWay().equals(SystemConstant.ORDER_PAY_ACCOUNT)) {
            //  在线;
            //  保存订单交易记录;
            saveOrderInfo(orderInfoVo, userId, orderNo);
            //  发送延迟队列消息取消订单;
            rabbitService.sendDealyMessage(MqConst.EXCHANGE_CANCEL_ORDER, MqConst.ROUTING_CANCEL_ORDER, orderNo, MqConst.CANCEL_ORDER_DELAY_TIME);
        } else {
            //  余额：需要一个远程调用;
            //  检查与锁定账户金额
            AccountDeductVo accountDeductVo = new AccountDeductVo();
            accountDeductVo.setOrderNo(orderNo);
            accountDeductVo.setUserId(userId);
            accountDeductVo.setAmount(orderInfoVo.getOrderAmount());
            accountDeductVo.setContent("订单支付");
            //  远程调用;
            Result result = userAccountFeignClient.checkAndDeduct(accountDeductVo);
            //  判断；
            if (200 != result.getCode()) {
                throw new GuiguException(result.getCode(), result.getMessage());
            }
            //  保存订单数据
            saveOrderInfo(orderInfoVo, userId, orderNo);
            //  需要修改订单状态;
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
            orderInfoMapper.update(orderInfo, new QueryWrapper<OrderInfo>().eq("order_no", orderNo));
            //  记录交易记录; 远程调用userInfoFeinClient;
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            userPaidRecordVo.setOrderNo(orderNo);
            userPaidRecordVo.setItemType(orderInfoVo.getItemType());
            userPaidRecordVo.setUserId(userId);
            //  购买类目的Id; 专辑Id, 声音Id, vipId = orderInfoVo.getOrderDetailVoList().itemId; = order_detail.item_id;
            List<Long> itemIdList = orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).collect(Collectors.toList());
            userPaidRecordVo.setItemIdList(itemIdList);
            //  远程调用：
            Result userResult = userInfoFeignClient.savePaidRecord(userPaidRecordVo);
            //  判断
            if (200 != userResult.getCode()) {
                throw new GuiguException(211, "新增购买记录异常");
            }
        }
        //  返回订单编号;
        return orderNo;
    }

    /**
     * 保存订单交易记录
     *
     * @param orderInfoVo
     * @param userId
     * @param orderNo
     */
    @Transactional(rollbackFor = Exception.class)
    private void saveOrderInfo(OrderInfoVo orderInfoVo, Long userId, String orderNo) {
        //  order_info
        OrderInfo orderInfo = new OrderInfo();
        //  属性拷贝：
        BeanUtils.copyProperties(orderInfoVo, orderInfo);
        orderInfo.setUserId(userId);
        orderInfo.setOrderTitle(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
        orderInfo.setOrderNo(orderNo);
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        orderInfoMapper.insert(orderInfo);
        //  order_detail
        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        if (!CollectionUtils.isEmpty(orderDetailVoList)) {
            for (OrderDetailVo orderDetailVo : orderDetailVoList) {
                //  创建对象
                OrderDetail orderDetail = new OrderDetail();
                //  赋值：
                orderDetail.setOrderId(orderInfo.getId());
                orderDetail.setItemId(orderDetailVo.getItemId());
                orderDetail.setItemName(orderDetailVo.getItemName());
                orderDetail.setItemUrl(orderDetailVo.getItemUrl());
                orderDetail.setItemPrice(orderDetailVo.getItemPrice());
                orderDetailMapper.insert(orderDetail);
            }
        }
        //  order_derate
        List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
        if (!CollectionUtils.isEmpty(orderDerateVoList)) {
            for (OrderDerateVo orderDerateVo : orderDerateVoList) {
                //  创建减免明细
                OrderDerate orderDerate = new OrderDerate();
                orderDerate.setOrderId(orderInfo.getId());
                orderDerate.setDerateType(orderDerateVo.getDerateType());
                orderDerate.setDerateAmount(orderDerateVo.getDerateAmount());
                orderDerate.setRemarks(orderDerateVo.getRemarks());
                orderDerateMapper.insert(orderDerate);
            }
        }
    }

    @Override
    public void cancelOrder(String orderNo) {
        //取消订单
        OrderInfo orderInfo = this.getOrderInfoByOrderNo(orderNo);
        //判断是否为空
        if (null == orderInfo){
            log.info("订单不存在：{}",orderNo);
            return;
        }
        //修改当前状态
        if (orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_PAID)){
            log.info("订单已支付：{}",orderNo);
            return;
        }
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);
        this.updateById(orderInfo);
    }


    public OrderInfo getOrderInfoByOrderNo(String orderNo) {
        //查询数据库
        OrderInfo orderInfo = this.getOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        if (null != orderInfo){
            //获取支付名称
            String payName = orderInfo.getPayWay().equals(SystemConstant.ORDER_PAY_ACCOUNT) ? "余额":"在线";
            //设置支付名称
            orderInfo.setPayWayName(payName);
        }
        //返回数据
        return orderInfo;
    }

    @Override
    public IPage<OrderInfo> findUserPage(Page<OrderInfo> orderInfoPage, Long userId, String orderStatus) {
        //调用mapper层方法
        IPage<OrderInfo> iPage = orderInfoMapper.selectUserPage(orderInfoPage,userId,orderStatus);
        iPage.getRecords().forEach(orderInfo -> {
            //赋值订单名称状态
            String orderStatusName = orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_UNPAID) ? "未支付" : orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_PAID) ? "已支付" : "取消";
            orderInfo.setOrderStatusName(orderStatusName);
            orderInfo.setPayWayName(orderInfo.getPayWay().equals(SystemConstant.ORDER_PAY_ACCOUNT) ? "余额":"在线");
        });
        return iPage;
    }


    @Override
    public void orderPaySuccess(String orderNo) {
        //修改订单状态
        OrderInfo orderInfo = this.getOrderInfoByOrderNo(orderNo);
        //判断
        if (null != orderInfo && orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_UNPAID)){
            //修改状态
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
            this.updateById(orderInfo);
            //创建 userPaidRecordVo
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            //赋值
            userPaidRecordVo.setOrderNo(orderInfo.getOrderNo());
            userPaidRecordVo.setUserId(orderInfo.getUserId());
            userPaidRecordVo.setItemType(orderInfo.getItemType());
            //itemIdList
            List<Long> itemIdList = orderInfo.getOrderDetailList().stream().map(OrderDetail::getItemId).collect(Collectors.toList());
            userPaidRecordVo.setItemIdList(itemIdList);
            //保存用户购买记录
            userInfoFeignClient.savePaidRecord(userPaidRecordVo);
        }
    }
}
